/**
 *  Copyright (C) 2006 zhangbo (freeeob@gmail.com)
 *
 *  This product is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  This product is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 *
 *  author:zhangbo
 *  Email:jsjava@gmail.com
 */

/**  The DefaultMutableTreeNode class references to javax.swing.tree.DefaultMutableTreeNode of J2SE1.4 */
 
/**
 * constructor
 */
function DefaultMutableTreeNode(userObject,allowsChildren){
	this.jsjava_class="jsjavax.swing.tree.DefaultMutableTreeNode";
	this.parent = null;
	this._children = null;
	this.allowsChildren = allowsChildren;
	if(allowsChildren==undefined){
		this.allowsChildren = false;
	}
	this.userObject = userObject;
	/**
	 * Creates and returns a forward-order enumeration of this node's children
	 * @param childIndex
	 */
	this.children=function(){
	    if (this._children == null) {
		    return new EMPTY_ENUMERATION();
		} else {
		    return this._children.elements();
		}	
	};
	this.getLeafCount=function(){
		var count = 0;
		var node;
		var enumer = new BreadthFirstEnumeration(this); 
		while (enumer.hasMoreElements()) {
		    node = enumer.nextElement();
		    if (node.isLeaf()) {
				count++;
		    }
		}
	
		if (count < 1) {
		    throw new Error("tree has zero leaves");
		}
		return count;
	};
	/**
	 * Creates and returns an enumeration that traverses the subtree rooted at this node in breadth-first order
	 */
	this.breadthFirstEnumeration=function(){
		return new BreadthFirstEnumeration(this);
	};
	/**
	 * Returns the depth of the tree rooted at this node -- the longest distance from this node to a leaf
	 */
	this.getDepth=function(){
		var	last = null;
		var	enumer = new BreadthFirstEnumeration(this);	
		while (enumer.hasMoreElements()) {
		    last = enumer.nextElement();
		}	
		if (last == null) {
		    throw new Error ("nodes should be null");
		}	
		return last.getLevel() - this.getLevel();
	};
	/**
	 * Creates and returns an enumeration that follows the path from ancestor to this node
	 */
	this.pathFromAncestorEnumeration=function(ancestor){
		return new PathBetweenNodesEnumeration(ancestor, this);
	};
	/**
	 * Creates and returns an enumeration that traverses the subtree rooted at this node in postorder
	 */
	this.postorderEnumeration=function(){
		return new PostorderEnumeration(this);
    };
    /**
	 * Creates and returns an enumeration that traverses the subtree rooted at this node in preorder
	 */
	this.preorderEnumeration=function(){
		return new PreorderEnumeration(this);
	};
	
	function EMPTY_ENUMERATION(){
		
	}	
	EMPTY_ENUMERATION.prototype=new Enumeration();
	EMPTY_ENUMERATION.prototype.constructor=EMPTY_ENUMERATION;
	EMPTY_ENUMERATION.prototype.hasMoreElements=function(){
	    return false;
	};
	EMPTY_ENUMERATION.prototype.nextElement=function(){
		throw new NoSuchElementException(NoSuchMethodException.ERROR,"No more elements");
	};
	
	function BreadthFirstEnumeration(rootNode){
    	var v = new Vector(1);
	    v.addElement(rootNode);	
	    this.queue = new Queue();
	    this.queue.enqueue(v.elements());
    }
    BreadthFirstEnumeration.prototype=new Enumeration();
    BreadthFirstEnumeration.prototype.constructor=BreadthFirstEnumeration;
    BreadthFirstEnumeration.prototype.hasMoreElements=function() {
	    return (!this.queue.isEmpty() && this.queue.firstObject().hasMoreElements());
	};
	BreadthFirstEnumeration.prototype.nextElement=function() {
	    var	enumer = this.queue.firstObject();
	    var	node = enumer.nextElement();
	    var	children = node.children();
	    if (!enumer.hasMoreElements()) {
			this.queue.dequeue();
	    }
	    if (children.hasMoreElements()) {
			this.queue.enqueue(children);
	    }
	    return node;
	};
	
	function PathBetweenNodesEnumeration(ancestor,descendant){
    	if (ancestor == null || descendant == null) {
			throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is null");
	    }
	    var current;
	    this.stack = new Stack();
	    this.stack.push(descendant);
	    current = descendant;
	    while (current != ancestor) {
			current = current.getParent();
			if (current == null && descendant != ancestor) {
			    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"node " + ancestor +
					" is not an ancestor of " + descendant);
			}
			this.stack.push(current);
	    }
    }
    PathBetweenNodesEnumeration.prototype=new Enumeration();
    PathBetweenNodesEnumeration.prototype.constructor=PathBetweenNodesEnumeration;
    PathBetweenNodesEnumeration.prototype.hasMoreElements=function(){
    	return this.stack.size() > 0;
    };
    PathBetweenNodesEnumeration.prototype.nextElement=function(){
    	try {
			return this.stack.pop();
	    } catch (e) {
			throw new NoSuchElementException(NoSuchElementException.ERROR,"No more elements");
	    }
    };
    
    function PostorderEnumeration(rootNode){
    	this.root = rootNode;
	    this.children = this.root.children();
	    this.subtree = new EMPTY_ENUMERATION();
    }
    PostorderEnumeration.prototype.hasMoreElements=function(){
    	return this.root != null;
    };
    PostorderEnumeration.prototype.nextElement=function(){
    	var retval;
	    if (this.subtree.hasMoreElements()) {
			retval = this.subtree.nextElement();
	    } else if (this.children.hasMoreElements()) {
			this.subtree = new PostorderEnumeration(
					this.children.nextElement());
			retval = this.subtree.nextElement();
	    } else {
			retval = this.root;
			this.root = null;
	    }
	    return retval;
    };
    
    function PreorderEnumeration(rootNode){
    	var v = new Vector(1);
	    v.addElement(rootNode);	
	    this.stack = new Stack();
	    this.stack.push(v.elements());
    }
    PreorderEnumeration.prototype=new Enumeration();
    PreorderEnumeration.prototype.constructor=PreorderEnumeration;
    PreorderEnumeration.prototype.hasMoreElements=function(){
    	return (!this.stack.empty() && this.stack.peek().hasMoreElements());
    };
    PreorderEnumeration.prototype.nextElement=function(){
    	var	enumer = this.stack.peek();
	    var	node = enumer.nextElement();
	    var	children = node.children();
	    if (!enumer.hasMoreElements()) {
			this.stack.pop();
	    }
	    if (children.hasMoreElements()) {
			this.stack.push(children);
	    }
	    return node;
    };
    
  	function Queue(){
  		var head;	
	    var tail;
  		function QNode(object, next) {
		    this.object = object;
		    this.next = next;
		}
		this.enqueue=function(anObject) {
			if (head == null) {
			    head = tail = new QNode(anObject, null);
			} else {
			    tail.next = new QNode(anObject, null);
			    tail = tail.next;
			}
	    };
	    this.dequeue=function() {
			if (head == null) {
			    throw new NoSuchElementException(NoSuchElementException.ERROR,"No more elements");
			}
			var retval = head.object;
			var oldHead = head;
			head = head.next;
			if (head == null) {
			    tail = null;
			} else {
			    oldHead.next = null;
			}
			return retval;
	    };
	    this.firstObject=function() {
			if (head == null) {
			    throw new NoSuchElementException(NoSuchElementException.ERROR,"No more elements");
			}	
			return head.object;
	    };

	    this.isEmpty=function() {
			return head == null;
	    };
  	}
}

DefaultMutableTreeNode.prototype=new MutableTreeNode();
DefaultMutableTreeNode.prototype.constructor=DefaultMutableTreeNode;

/**
 * Removes newChild from its parent and makes it a child of this node by adding it to the end of this node's child array
 */
DefaultMutableTreeNode.prototype.add=function(newChild){
    if(newChild != null && newChild.getParent() == this){
	    this.insert(newChild, this.getChildCount() - 1);
	}else
	    this.insert(newChild, this.getChildCount());
	}
};


/**
 * Overridden to make clone public
 */
DefaultMutableTreeNode.prototype.clone=function(){
    return null;
};

/**
 * Creates and returns an enumeration that traverses the subtree rooted at this node in depth-first order
 */
DefaultMutableTreeNode.prototype.depthFirstEnumeration=function(){
    return postorderEnumeration();
};

/**
 * Returns true if this node is allowed to have children
 */
DefaultMutableTreeNode.prototype.getAllowsChildren=function(aChild){
    return this.allowsChildren;
};

/**
 * Returns the child in this node's child array that immediately follows aChild, which must be a child of this node
 */
DefaultMutableTreeNode.prototype.getChildAfter=function(aChild){
    if (aChild == null) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is null");
	}

	var index = this.getIndex(aChild);		

	if (index == -1) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"node is not a child");
	}

	if (index < this.getChildCount() - 1) {
	    return this.getChildAt(index + 1);
	} else {
	    return null;
	}
};

/**
 * Returns the child at the specified index in this node's child array
 */
DefaultMutableTreeNode.prototype.getChildAt=function(index){
    if (this._children == null) {
	    throw new ArrayIndexOutOfBoundsException(ArrayIndexOutOfBoundsException.ERROR,"node has no children");
	}
	return this._children.elementAt(index);
};

/**
 * Returns the child in this node's child array that immediately precedes aChild, which must be a child of this node
 */
DefaultMutableTreeNode.prototype.getChildBefore=function(aChild){
    if (aChild == null) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is null");
	}

	var index = this.getIndex(aChild);		

	if (index == -1) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is not a child");
	}

	if (index > 0) {
	    return this.getChildAt(index - 1);
	} else {
	    return null;
	}
};

/**
 * Returns the number of children of this node
 */
DefaultMutableTreeNode.prototype.getChildCount=function(){
    if (this._children == null) {
	    return 0;
	} else {
	    return this._children.size();
	}
};

/**
 * Returns this node's first child
 */
DefaultMutableTreeNode.prototype.getFirstChild=function(){
    if (getChildCount() == 0) {
	    throw new NoSuchElementException(NoSuchElementException.ERROR,"node has no children");
	}
	return this.getChildAt(0);
};

/**
 * Finds and returns the first leaf that is a descendant of this node -- either this node or its first child's first leaf
 */
DefaultMutableTreeNode.prototype.getFirstLeaf=function(){
    var node = this;
	while (!node.isLeaf()) {
	    node = node.getFirstChild();
	}
	return node;
};

/**
 * Returns the index of the specified child in this node's child array
 */
DefaultMutableTreeNode.prototype.getIndex=function(aChild){
    if (aChild == null) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is null");
	}

	if (!this.isNodeChild(aChild)) {
	    return -1;
	}
	return this._children.indexOf(aChild)
};

/**
 * Returns this node's last child
 */
DefaultMutableTreeNode.prototype.getLastChild=function(){
    if (getChildCount() == 0) {
	    throw new NoSuchElementException(NoSuchElementException.ERROR,"node has no children");
	}
	return this.getChildAt(this.getChildCount()-1);
};

/**
 * Finds and returns the last leaf that is a descendant of this node -- either this node or its last child's last leaf
 */
DefaultMutableTreeNode.prototype.getLastLeaf=function(){
    var node = this;
	while (!node.isLeaf()) {
	    node = node.getLastChild();
	}
	return node;
};

/**
 * Returns the number of levels above this node -- the distance from the root to this node
 */
DefaultMutableTreeNode.prototype.getLevel=function(){
    var ancestor;
	var levels = 0;
	ancestor = this;
	while((ancestor = ancestor.getParent()) != null){
	    levels++;
	}
	return levels;
};

/**
 * Returns the leaf after this node or null if this node is the last leaf in the tree
 */
DefaultMutableTreeNode.prototype.getNextLeaf=function(){
    var nextSibling;
	var myParent = this.getParent();
	if (myParent == null)
	    return null;
	nextSibling = this.getNextSibling();	
	if (nextSibling != null)
	    return nextSibling.getFirstLeaf();

	return myParent.getNextLeaf();
};

/**
 * Returns the node that follows this node in a preorder traversal of this node's tree
 */
DefaultMutableTreeNode.prototype.getNextNode=function(){
    if (this.etChildCount() == 0) {
	    var nextSibling = this.getNextSibling();
	    if (nextSibling == null) {
			var aNode = this.getParent();
			do {
			    if (aNode == null) {
					return null;
			    }
			    nextSibling = aNode.getNextSibling();
			    if (nextSibling != null) {
					return nextSibling;
			    }
			    aNode = aNode.getParent();
			} while(true);
	    } else {
			return nextSibling;
	    }
	} else {
	    return this.getChildAt(0);
	}
};

/**
 * Returns the next sibling of this node in the parent's children array
 */
DefaultMutableTreeNode.prototype.getNextSibling=function(){
    var retval;
	var myParent = this.getParent();
	if (myParent == null) {
	    retval = null;
	} else {
	    retval = myParent.getChildAfter(this);	
	}
	if (retval != null && !this.isNodeSibling(retval)) {
	    throw new Error("child of parent is not a sibling");
	}
	return retval;
};

/**
 * Returns this node's parent or null if this node has no parent
 */
DefaultMutableTreeNode.prototype.getParent=function(){
    return this.parent
};

/**
 * Returns the path from the root, to get to this node
 */
DefaultMutableTreeNode.prototype.getPath=function(){
	return this.getPathToRoot(this, 0)
};

/**
 * Builds the parents of node up to and including the root node, where the original node is the last element in the returned array
 */
DefaultMutableTreeNode.prototype.getPathToRoot=function(aNode,depth){
    var retNodes;
	if(aNode == null) {
	    if(depth == 0)
			return null;
	    else{
			retNodes = new Array(depth);
		}
	}
	else {
	    depth++;
	    retNodes = this.getPathToRoot(aNode.getParent(), depth);
	    retNodes[retNodes.length - depth] = aNode;
	}
	return retNodes
};

/**
 * Returns the leaf before this node or null if this node is the first leaf in the tree
 */
DefaultMutableTreeNode.prototype.getPreviousLeaf=function(){
    var previousSibling;
	var myParent = this.getParent();
	if (myParent == null)
	    return null;
	previousSibling = this.getPreviousSibling();	
	if (previousSibling != null)
	    return previousSibling.getLastLeaf();
	return myParent.getPreviousLeaf();
};

/**
 * Returns the node that precedes this node in a preorder traversal of this node's tree
 */
DefaultMutableTreeNode.prototype.getPreviousNode=function(){
    var previousSibling;
	var myParent = this.getParent();
	if (myParent == null) {
	    return null;
	}
	previousSibling = this.getPreviousSibling();
	if (previousSibling != null) {
	    if (previousSibling.getChildCount() == 0)
			return previousSibling;
	    else{
			return previousSibling.getLastLeaf();
		}
	} else {
	    return myParent;
	}
};

/**
 * Returns the previous sibling of this node in the parent's children array
 */
DefaultMutableTreeNode.prototype.getPreviousSibling=function(){
    var retval;
	var myParent = this.getParent();
	if (myParent == null) {
	    retval = null;
	} else {
	    retval = myParent.getChildBefore(this);	
	}
	if (retval != null && !this.isNodeSibling(retval)) {
	    throw new Error("child of parent is not a sibling");
	}
	return retval;
};

/**
 * Returns the root of the tree that contains this node
 */
DefaultMutableTreeNode.prototype.getRoot=function(){
    var ancestor = this;
	var previous;
	do {
	    previous = ancestor;
	    ancestor = ancestor.getParent();
	} while (ancestor != null);
	return previous;
};

/**
 * Returns the nearest common ancestor to this node and aNode
 */
DefaultMutableTreeNode.prototype.getSharedAncestor=function(aNode){
    if (aNode == this) {
	    return this;
	} else if (aNode == null) {
	    return null;
	}
	var	level1, level2, diff;
	var	node1, node2;	
	level1 = this.getLevel();
	level2 = aNode.getLevel();	
	if (level2 > level1) {
	    diff = level2 - level1;
	    node1 = aNode;
	    node2 = this;
	} else {
	    diff = level1 - level2;
	    node1 = this;
	    node2 = aNode;
	}

	while (diff > 0) {
	    node1 = node1.getParent();
	    diff--;
	}
	
	do {
	    if (node1 == node2) {
			return node1;
	    }
	    node1 = node1.getParent();
	    node2 = node2.getParent();
	} while (node1 != null);
	if (node1 != null || node2 != null) {
	    throw new Error ("nodes should be null");
	}
	
	return null;
};

/**
 * Returns the number of siblings of this node
 */
DefaultMutableTreeNode.prototype.getSiblingCount=function(){
    var myParent = this.getParent();
	if (myParent == null) {
	    return 1;
	} else {
	    return myParent.getChildCount();
	}
};

/**
 * Returns this node's user object
 */
DefaultMutableTreeNode.prototype.getUserObject=function(){
    return this.userObject;
};

/**
 * Returns the user object path, from the root, to get to this node
 */
DefaultMutableTreeNode.prototype.getUserObjectPath=function(){
    var realPath = this.getPath();
	var retPath = new Array(realPath.length);
	for(var counter = 0; counter < realPath.length; counter++)
	    retPath[counter] = realPath[counter].getUserObject();
	return retPath;
};

/**
 * Removes newChild from its present parent (if it has a parent), sets the child's parent to this node, and then adds the child to this node's child array at index childIndex
 */
DefaultMutableTreeNode.prototype.insert=function(newChild,childIndex){
    if (!this.allowsChildren) {
	    throw new IllegalStateException(IllegalStateException.ERROR,"node does not allow children");
	} else if (newChild == null) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"new child is null");
	} else if (this.isNodeAncestor(newChild)) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"new child is an ancestor");
	}
    var oldParent = newChild.getParent();
    if (oldParent != null) {
		oldParent.remove(newChild);
    }
    newChild.setParent(this);
    if (this._children == null) {
		this._children = new Vector();
    }
    this._children.insertElementAt(newChild, childIndex);
};

/**
 * Returns true if this node has no children
 */
DefaultMutableTreeNode.prototype.isLeaf=function(){
    return (this.getChildCount() == 0);
};

/**
 * Returns true if anotherNode is an ancestor of this node -- if it is this node, this node's parent, or an ancestor of this node's parent
 */
DefaultMutableTreeNode.prototype.isNodeAncestor=function(anotherNode){
    if (anotherNode == null) {
	    return false;
	}
	var ancestor = this;
	do {
	    if (ancestor == anotherNode) {
			return true;
	    }
	} while((ancestor = ancestor.getParent()) != null);
	return false;
};

/**
 * Returns true if aNode is a child of this node
 */
DefaultMutableTreeNode.prototype.isNodeChild=function(aNode){
    var retval;
	if (aNode == null) {
	    retval = false;
	} else {
	    if (this.getChildCount() == 0) {
			retval = false;
	    } else {
			retval = (aNode.getParent() == this);
	    }
	}
	return retval;
};

/**
 * Returns true if anotherNode is a descendant of this node -- if it is this node, one of this node's children, or a descendant of one of this node's children
 */
DefaultMutableTreeNode.prototype.isNodeDescendant=function(anotherNode){
    if (anotherNode == null)
	    return false;
	return anotherNode.isNodeAncestor(this);
};

/**
 * Returns true if and only if aNode is in the same tree as this node
 */
DefaultMutableTreeNode.prototype.isNodeRelated=function(aNode){
    return (aNode != null) && (this.getRoot() == aNode.getRoot());
};

/**
 * Returns true if anotherNode is a sibling of (has the same parent as) this node
 */
DefaultMutableTreeNode.prototype.isNodeSibling=function(anotherNode){
    var retval;
	if (anotherNode == null) {
	    retval = false;
	} else if (anotherNode == this) {
	    retval = true;
	} else {
	    var  myParent = this.getParent();
	    retval = (myParent != null && myParent == anotherNode.getParent());
	    if (retval && !this.getParent().isNodeChild(anotherNode)) {
			throw new Error("sibling has different parent");
	    }
	}
	return retval;
};

/**
 * Returns true if this node is the root of the tree
 */
DefaultMutableTreeNode.prototype.isRoot=function(){
    return this.getParent() == null;
};

/**
 * Removes the child at the specified index from this node's children and sets that node's parent to null
 */
DefaultMutableTreeNode.prototype.remove=function(childIndex){
    var child = this.getChildAt(childIndex);
	this._children.removeElementAt(childIndex);
	child.setParent(null);
};

/**
 * Removes aChild from this node's child array, giving it a null parent
 */
DefaultMutableTreeNode.prototype.remove=function(aChild){
    if (aChild == null) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is null");
	}

	if (!this.isNodeChild(aChild)) {
	    throw new IllegalArgumentException(IllegalArgumentException.ERROR,"argument is not a child");
	}
	this.remove(this.getIndex(aChild));	
};

/**
 * Removes all of this node's children, setting their parents to null
 */
DefaultMutableTreeNode.prototype.removeAllChildren=function(){
    for (var i = this.getChildCount()-1; i >= 0; i--) {
	    this.remove(i);
	}
};

/**
 * Removes the subtree rooted at this node from the tree, giving this node a null parent
 */
DefaultMutableTreeNode.prototype.removeFromParent=function(){
    var parent = this.getParent();
	if (parent != null) {
	    parent.remove(this);
	}
};

/**
 * Determines whether or not this node is allowed to have children
 */
DefaultMutableTreeNode.prototype.setAllowsChildren=function(allows){
    if (allows != this.llowsChildren) {
	    allowsChildren = allows;
	    if (!allowsChildren) {
			this.removeAllChildren();
	    }
	}
};

/**
 * Sets this node's parent to newParent but does not change the parent's child array
 */
DefaultMutableTreeNode.prototype.setParent=function(newParent){
    this.parent = newParent;
};

/**
 * Sets the user object for this node to userObject
 */
DefaultMutableTreeNode.prototype.setUserObject=function(userObject){
    this.userObject = userObject;
};

/**
 * Returns the result of sending toString() to this node's user object, or null if this node has no user object
 */
DefaultMutableTreeNode.prototype.toString=function(){
    if (this.userObject == null) {
	    return null;
	} else {
	    return this.userObject.toString();
	}
};